package com.shixj.ef.config;

import com.shixj.ef.core.DefaultHttpFetcher;
import com.shixj.ef.core.FetchDocumentHandler;
import com.shixj.ef.core.FetchHttpEntityHandler;
import com.shixj.ef.core.HttpFetcher;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * Created by shixj on 2017/9/19.
 */
public class FetchConfig {
    private  int socketTimeout=20000;
    private  int connectionTimeout=20000;
    private HttpFetcher fetcher;
    private int depth = -1;
    private String initUrl;
    private int threadLimit = 1;
    private Long delayTime = 5000L;
    private Long sleepInterval = 500L;
    private int max = -1;
    private String regex;//
    private Map<Integer, String> depthRegexMap = new HashMap();
    boolean async=true;

    public static FetchDocumentHandler documentHandler;



    public  FetchConfig setDocumentHandler(FetchDocumentHandler documentHandler) {
        FetchConfig.documentHandler = documentHandler;
        return this;
    }

    public boolean isAsync() {
        return async;
    }

    public FetchConfig setAsync(boolean async) {
        this.async = async;
        return this;
    }

    public int getSocketTimeout() {
        return socketTimeout;
    }

    public FetchConfig setSocketTimeout(int socketTimeout) {
        this.socketTimeout = socketTimeout;
        return this;
    }

    public int getConnectionTimeout() {
        return connectionTimeout;
    }

    public FetchConfig setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
        return this;
    }

    public String getRegex() {
        return regex;
    }

    public FetchConfig setRegex(String regex) {
        this.regex = regex;
        return this;
    }

    public String getDepthRegex(Integer depthIndex) {
        return depthRegexMap.get(depthIndex);
    }

    public FetchConfig setDepthRegex(Integer depthIndex, String regex) {
        this.depthRegexMap.put(depthIndex, regex);
        return this;
    }

    public Map<Integer, String> getDepthRegexMap() {
        return depthRegexMap;
    }

    public FetchConfig setDepthRegexMap(Map<Integer, String> depthRegexMap) {
        this.depthRegexMap = depthRegexMap;
        return this;
    }

    public Long getSleepInterval() {
        return sleepInterval;
    }

    public FetchConfig setSleepInterval(Long sleepInterval) {
        this.sleepInterval = sleepInterval;
        return this;
    }

    public int getMax() {
        return max;
    }

    public FetchConfig setMax(int max) {
        this.max = max;
        return this;
    }

    public int getThreadLimit() {
        return threadLimit;
    }

    public FetchConfig setThreadLimit(int threadLimit) {
        this.threadLimit = threadLimit;
        return this;
    }

    public Long getDelayTime() {
        return delayTime;
    }

    public FetchConfig setDelayTime(Long delayTime) {
        this.delayTime = delayTime;
        return this;
    }

    public int getDepth() {
        return depth;
    }

    public FetchConfig setDepth(int depth) {
        this.depth = depth;
        return this;
    }


    public String getInitUrl() {
        return initUrl;
    }

    public FetchConfig setInitUrl(String initUrl) {
        this.initUrl = initUrl;
        return this;
    }

    public FetchConfig(String initUrl) {
        this.initUrl = initUrl;
    }

    public static FetchConfig bulid(String initUrl) {
        FetchConfig fetchConfig=new FetchConfig(initUrl);
        fetchConfig.fetcher=new DefaultHttpFetcher(fetchConfig);
        return fetchConfig;
    }

    public HttpFetcher start() {
        CloseableHttpClient httpClient=  createClient();
        this.fetcher.start(httpClient);
        return this.fetcher;
    }

    private  CloseableHttpClient createClient(){
        HttpClientBuilder clientBuilder = HttpClientBuilder.create();
        RequestConfig requestConfig = RequestConfig.custom().setExpectContinueEnabled(false).setCookieSpec("default")
                .setRedirectsEnabled(false)
                        .setSocketTimeout(socketTimeout).setConnectTimeout(connectionTimeout).build();
        clientBuilder.setDefaultRequestConfig(requestConfig);

        RegistryBuilder<ConnectionSocketFactory> connRegistryBuilder = RegistryBuilder.create();
        connRegistryBuilder.register("http", PlainConnectionSocketFactory.INSTANCE);
        try {
             SSLConnectionSocketFactory sslsf = null;
            PoolingHttpClientConnectionManager cm = null;
             SSLContextBuilder builder = null;
            builder = new SSLContextBuilder();
            // 全部信任 不做身份鉴定
            builder.loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                    return true;
                }
            });
            sslsf = new SSLConnectionSocketFactory(builder.build(), new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);
            connRegistryBuilder.register("https", sslsf);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Registry<ConnectionSocketFactory> connRegistry = connRegistryBuilder.build();
        PoolingHttpClientConnectionManager connectionManager;
        connectionManager = new PoolingHttpClientConnectionManager(connRegistry);
        connectionManager.setMaxTotal(50);
        connectionManager.setDefaultMaxPerRoute(50);
        clientBuilder.setConnectionManager(connectionManager);
      /*  clientBuilder.setUserAgent(config.getUserAgentString());*/
        clientBuilder.setDefaultHeaders(new HashSet());
        return clientBuilder.build();
    }
}
